package com.alibaba.citrus.cr.unified.inventory.functions.handler;

import com.alibaba.citrus.cr.unified.inventory.model.enums.ReceiveStatus;
import com.alibaba.citrus.cr.unified.inventory.model.enums.ShipStatus;
import com.alibaba.citrus.cr.unified.inventory.utils.CompareUtil;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.epoch.app.crunifiedinventory.domain.allocateorderdetail.model.AllocateOrderDetail;
import com.epoch.app.crunifiedinventory.model.enums.AllocateOrderStatus;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/**
 * @description: 计划调拨单->货场仓收货
 * @author: yuhw
 * @date: 2024年01月27日 10:59
 **/
@Component("plan2FreightYardAllocateOrderStatusCompute")
public class Plan2FreightYardAllocateOrderStatusCompute extends StatusCompute{
    private static Log log = Log.getLogger(Plan2FreightYardAllocateOrderStatusCompute.class);
    private static final String SPLIT = ":";

    private static Map<String,AllocateOrderStatus> statusMap = Maps.newHashMap();

    static {
        statusMap.put(key(ShipStatus.NONE,ReceiveStatus.NONE),AllocateOrderStatus.Shipment_Processing);
        statusMap.put(key(ShipStatus.NONE,ReceiveStatus.PART),AllocateOrderStatus.SHIPMENT_PROCESSING_YARD_PART_RECEIVED);
        statusMap.put(key(ShipStatus.NONE,ReceiveStatus.ALL),AllocateOrderStatus.SHIPMENT_PROCESSING_YARD_RECEIVED);
        statusMap.put(key(ShipStatus.PART,ReceiveStatus.NONE),AllocateOrderStatus.PART_SHIPPED_YARD_NONE_RECEIVED);
        statusMap.put(key(ShipStatus.PART,ReceiveStatus.PART),AllocateOrderStatus.PART_SHIPPED_YARD_PART_RECEIVED);
        statusMap.put(key(ShipStatus.PART,ReceiveStatus.ALL),AllocateOrderStatus.PART_SHIPPED_YARD_RECEIVED);
        statusMap.put(key(ShipStatus.ALL,ReceiveStatus.NONE),AllocateOrderStatus.ALL_SHIPPED_YARD_NONE_RECEIVED);
        statusMap.put(key(ShipStatus.ALL,ReceiveStatus.PART),AllocateOrderStatus.ALL_SHIPPED_YARD_PART_RECEIVED);
        statusMap.put(key(ShipStatus.ALL,ReceiveStatus.ALL),AllocateOrderStatus.ALL_SHIPPED_YARD_RECEIVED);
        //还有个两个枚举 已完成 和 已发货,部分提货完成
        /**
         * 计算本身的状态, 再根据货场提货单的状态再来计算计划调拨单有货场仓的场景
         */
    }

    /**
     *  自身的状态推送完成后, 还需要依赖货场提货单的状态
     */

    @Override
    public AllocateOrderStatus process(ShipStatus shipStatus, ReceiveStatus receiveStatus, Map<String, AllocateOrderStatus> statusMap) {
        //TODO 这里判断下特殊场景 即如果是已取消的就不再改变状态了.
        return statusMap.get(key(shipStatus,receiveStatus));
    }

    /**
     * 此处为所有货场仓的状态, 用此进行计算计划单对应明细行的状态
     * 明细行状态 -> 聚合到明细行上
     * @param statusList
     * @return
     */
    public AllocateOrderStatus computeLineMainStatusList(List<AllocateOrderStatus> statusList){
        //这些status是属于货场仓明细, 所以他们的状态
        int shipNoneCount = 0;
        int shipPartCount = 0;
        int shipAllCount = 0;
        int receiveAllCount = 0;
        int receivePartCount = 0;
        int receiveNoneCount = 0;
        int cancelCount = 0;
        int draftCount = 0;
        int waitPushCount = 0;
        for (AllocateOrderStatus status : statusList) {
            switch (status){
                case Shipment_Processing:
                    shipNoneCount++;
                    receiveNoneCount++;
                    break;
                case SHIPMENT_PROCESSING_PART_RECEIVED:
                    shipNoneCount++;
                    receivePartCount++;
                    break;
                case SHIPMENT_PROCESSING_RECEIVED:
                    shipNoneCount++;
                    receiveAllCount++;
                    receivePartCount++;
                case PART_SHIPPED_NONE_RECEIVED:
                    shipPartCount++;
                    receiveNoneCount++;
                    break;
                case PART_SHIPPED_PART_RECEIVED:
                    shipPartCount++;
                    receivePartCount++;
                    break;
                case PART_SHIPPED_RECEIVED:
                    shipPartCount++;
                    receiveAllCount++;
                    receivePartCount++;
                    break;
                case ALL_SHIPPED_NONE_RECEIVED:
                    shipAllCount++;
                    receiveNoneCount++;
                    shipPartCount++;
                    break;
                case ALL_SHIPPED_PART_RECEIVED:
                    shipAllCount++;
                    receivePartCount++;
                    shipPartCount++;
                    break;
                case COMPLETED:
                    shipAllCount++;
                    receiveAllCount++;
                    shipPartCount++;
                    receivePartCount++;
                    break;
                case WAIT_PUSH:
                    waitPushCount++;
                    break;
                case Cancel:
                    cancelCount++;
                    break;
                default:break;
            }
        }
        boolean allWaitPush = statusList.stream().allMatch(status -> AllocateOrderStatus.WAIT_PUSH.equals(status));
        boolean allCancel = statusList.stream().allMatch(status -> AllocateOrderStatus.Cancel.equals(status));
        long count = statusList.stream().filter(status -> !CompareUtil.anyOf(status, AllocateOrderStatus.Cancel, AllocateOrderStatus.WAIT_PUSH)).count();
        log.info("plan2FreightYardAllocateOrderStatusCompute,allWaitPush:{},allCancel:{},count:{},shipAllCount:{},receiveAllCount:{},shipPartCount:{},receivePartCount:{}," +
                "shipNoneCount:{},receiveNoneCount:{}",allWaitPush,allCancel,count,shipAllCount,receiveAllCount,shipPartCount,receivePartCount,shipNoneCount,receiveNoneCount);
        //货场提货单子单状态计算出 关联单的明细状态
        if (allCancel || allWaitPush){
            //TODO 则不改变状态
            return null;
        }else if (shipAllCount == count && receiveAllCount == count){
            return AllocateOrderStatus.COMPLETED;
        }else if (shipAllCount == count && receivePartCount > 0){
            return AllocateOrderStatus.ALL_SHIPPED_PART_FINAL_RECEIVED;
        }else if (receiveAllCount == count){
            return AllocateOrderStatus.COMPLETED;
        }else if (receivePartCount > 0){
            return AllocateOrderStatus.ALL_SHIPPED_PART_FINAL_RECEIVED;
        }
        //TODO 如果提货单没有收货,那就不推进关联单的状态
//        else if(shipAllCount == count && receiveNoneCount == count){
//            return AllocateOrderStatus.ALL_SHIPPED_YARD_RECEIVED;
//        }else if (shipPartCount > 0 && receivePartCount > 0){
//            return AllocateOrderStatus.PART_SHIPPED_PART_RECEIVED;
//        }else if (shipPartCount > 0 && receiveNoneCount == count){
//            return AllocateOrderStatus.PART_SHIPPED_NONE_RECEIVED;
//        }else if (shipNoneCount == count && receiveAllCount == count){
//            return AllocateOrderStatus.SHIPMENT_PROCESSING_RECEIVED;
//        }else if (shipNoneCount == count && receivePartCount > 0){
//            return AllocateOrderStatus.SHIPMENT_PROCESSING_PART_RECEIVED;
//        }else if (shipNoneCount == count && receiveNoneCount == count){
//            return AllocateOrderStatus.Shipment_Processing;
//        }
        //null的时候建议保持原状态
        return null;
    }

    public AllocateOrderStatus computePlanOrderFreightYardMainStatus(List<AllocateOrderStatus> statusList){
        //假如都到这一步了,是不是应该已经处于已发货货场仓已收货;
        int pickedNoneCount = 0;
        int pickedPartCount = 0;
        int pickedAllCount = 0;
        int shipNoneCount = 0;
        int shipPartCount = 0;
        int shipAllCount = 0;
        int receiveAllCount = 0;
        int receivePartCount = 0;
        int receiveNoneCount = 0;
        for (AllocateOrderStatus status : statusList) {
            switch (status){
                case ALL_SHIPPED_PART_FINAL_RECEIVED:
                    pickedPartCount++;
                    break;
                case COMPLETED:
                    pickedAllCount++;
                    pickedPartCount++;//单行完成,至少也算是部分;
                    break;
                case ALL_SHIPPED_YARD_RECEIVED:
                    pickedNoneCount++;
                    break;
                default:break;
            }
        }
        boolean allWaitPush = statusList.stream().allMatch(status -> AllocateOrderStatus.WAIT_PUSH.equals(status));
        boolean allCancel = statusList.stream().allMatch(status -> AllocateOrderStatus.Cancel.equals(status));
        long count = statusList.stream().filter(status -> !CompareUtil.anyOf(status, AllocateOrderStatus.Cancel, AllocateOrderStatus.WAIT_PUSH)).count();
        log.info("plan2FreightYardAllocateOrderStatusCompute,allWaitPush:{},allCancel:{},count:{},shipAllCount:{},receiveAllCount:{},shipPartCount:{},receivePartCount:{}," +
                "shipNoneCount:{},receiveNoneCount:{},pickedNoneCount:{},pickedPartCount:{},pickedAllCount:{}",allWaitPush,allCancel,count,shipAllCount,receiveAllCount,shipPartCount,receivePartCount,shipNoneCount,receiveNoneCount,
                pickedNoneCount,pickedPartCount,pickedAllCount);
        if (allCancel){
            return AllocateOrderStatus.Cancel;
        }else if (allWaitPush){
            return AllocateOrderStatus.WAIT_PUSH;
        }else if (pickedAllCount == count){
            return AllocateOrderStatus.COMPLETED;
        }else if (pickedPartCount > 0){
            return AllocateOrderStatus.ALL_SHIPPED_PART_FINAL_RECEIVED;
        }else if (pickedNoneCount == count){
            return AllocateOrderStatus.ALL_SHIPPED_YARD_RECEIVED;
        }
        //TODO 状态匹配情况
        return null;
    }

    @Override
    public AllocateOrderStatus computeMainStatus(List<AllocateOrderStatus> statusList) {
        //这是计划调拨单自身推进状态时使用 TODO 这次暂时不考虑货场仓提货后再变更状态
        log.info("computeMainStatus_list:{}", JSON.toJSONString(statusList));
        int shipNoneCount = 0;
        int shipPartCount = 0;
        int shipAllCount = 0;
        int receiveNoneCount = 0;
        int receivePartCount = 0;
        int receiveAllCount = 0;
        int cancelCount = 0;
        int draftCount = 0;
        int waitPushCount = 0;
        for (AllocateOrderStatus status : statusList) {
            switch (status){
                case Shipment_Processing:
                    shipNoneCount++;
                    receiveNoneCount++;
                    break;
                case SHIPMENT_PROCESSING_YARD_PART_RECEIVED:
                    shipNoneCount++;
                    receivePartCount++;
                    break;
                case SHIPMENT_PROCESSING_YARD_RECEIVED:
                    shipNoneCount++;
                    receiveAllCount++;
                    receivePartCount++;
                case PART_SHIPPED_YARD_NONE_RECEIVED:
                    shipPartCount++;
                    receiveNoneCount++;
                    break;
                case PART_SHIPPED_YARD_PART_RECEIVED:
                    shipPartCount++;
                    receivePartCount++;
                    break;
                case PART_SHIPPED_YARD_RECEIVED:
                    shipPartCount++;
                    receiveAllCount++;
                    receivePartCount++;
                    break;
                case ALL_SHIPPED_YARD_NONE_RECEIVED:
                    shipAllCount++;
                    shipPartCount++;
                    receiveNoneCount++;
                    break;
                case ALL_SHIPPED_YARD_PART_RECEIVED:
                    shipAllCount++;
                    shipPartCount++;
                    receivePartCount++;
                    break;
                case ALL_SHIPPED_YARD_RECEIVED:
                    shipAllCount++;
                    receiveAllCount++;
                    shipPartCount++;
                    receivePartCount++;
                    break;
                case WAIT_PUSH:
                    waitPushCount++;
                    break;
                case Cancel:
                    cancelCount++;
                    break;
                default:
            }
        }
        boolean allWaitPush = statusList.stream().allMatch(status -> AllocateOrderStatus.WAIT_PUSH.equals(status));
        boolean allCancel = statusList.stream().allMatch(status -> AllocateOrderStatus.Cancel.equals(status));
        long count = statusList.stream().filter(status -> !CompareUtil.anyOf(status, AllocateOrderStatus.Cancel, AllocateOrderStatus.WAIT_PUSH)).count();
        log.info("plan2FreightYardAllocateOrderStatusCompute,allWaitPush:{},allCancel:{},count:{},shipAllCount:{},receiveAllCount:{},shipPartCount:{},receivePartCount:{}," +
                "shipNoneCount:{},receiveNoneCount:{}",allWaitPush,allCancel,count,shipAllCount,receiveAllCount,shipPartCount,receivePartCount,shipNoneCount,receiveNoneCount);
        if (allCancel){
            return AllocateOrderStatus.Cancel;
        }else if (allWaitPush){
            return AllocateOrderStatus.WAIT_PUSH;
        }else if (shipAllCount == count && receiveAllCount == count){
            return AllocateOrderStatus.ALL_SHIPPED_YARD_RECEIVED;
        }else if (shipAllCount == count && receivePartCount > 0){
            return AllocateOrderStatus.ALL_SHIPPED_YARD_PART_RECEIVED;
        }else if (shipAllCount == count && receiveNoneCount == count){
            return AllocateOrderStatus.ALL_SHIPPED_YARD_NONE_RECEIVED;
        }else if (shipPartCount > 0 && receiveAllCount == count){
            return AllocateOrderStatus.PART_SHIPPED_YARD_RECEIVED;
        }else if (shipPartCount > 0 && receivePartCount > 0){
            return AllocateOrderStatus.PART_SHIPPED_YARD_PART_RECEIVED;
        }else if (shipPartCount > 0 && receiveNoneCount == count){
            return AllocateOrderStatus.PART_SHIPPED_YARD_NONE_RECEIVED;
        }else if (shipNoneCount == count && receiveAllCount == count){
            return AllocateOrderStatus.SHIPMENT_PROCESSING_YARD_RECEIVED;
        }else if (shipNoneCount == count && receivePartCount > 0){
            return AllocateOrderStatus.SHIPMENT_PROCESSING_YARD_PART_RECEIVED;
        }else if (shipNoneCount == count && receiveNoneCount == count){
            return AllocateOrderStatus.Shipment_Processing;
        }
        return null;
    }

    @Override
    public Map<String, AllocateOrderStatus> getStatusMap() {
        return statusMap;
    }

    private static String key(ShipStatus shipStatus, ReceiveStatus receiveStatus){
        return shipStatus.name() + SPLIT + receiveStatus.name();
    }


}
